﻿
/// <reference path="Component.js" />
/// <reference path="_namespace.js" />
/// <reference path="MenuItemDisplayFlags.js" />

/*****************************************************************************
Ajax library class definition. Kevin Robinson 2006.
Class: ajax.components.ConfigurableComponent
/*****************************************************************************/


ajax.lang.addNamespace("ajax.components");
$imports("ajax.components.MenuItemDisplayFlags");

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent = function(doc) // Cibstructor
{
    ajax.components.ConfigurableComponent.superConstructor.call(this, doc);
    
    // These 2 properties are for the Config menu
    this.configurationMenu = null;
    this.configureTriggers = new Array();
    
    // The rest of these are for persisting data back to the server.
    this.configureSave      = null;  // ContentLoader
    this.configureLoad      = null;  // ContentLoader
    // By wiring up this event router, the load & save HTTP requests have a default target
    // to callback to, and the default handler's are run. Most clients would not need anything else.
    // But if they did then this handler could be removen and replaced with other custom callbacks.
    this.getEvent(this.window, "onConfigureLoad").addListener(this.onConfigureLoadHandler);
    this.getEvent(this.window, "onConfigureSave").addListener(this.onConfigureSaveHandler);
    // Default objects to export & import
    this.exported = new Object();
    this.imported = new Object();
}

//-----------------------------------------------------------------------------
ajax.lang.extend("ajax.components.ConfigurableComponent", "ajax.components.Component"); // Inherit

//-----------------------------------------------------------------------------
// These 2 methods should be overridden to cherry pick what to export & import
// OVERRIDE 1
ajax.components.ConfigurableComponent.prototype.exportConfiguration = function()
{
    // this is where custom properties can be cherry picked from any object into the "this.exported" object for saving
}

//-----------------------------------------------------------------------------
// OVERRIDE 2
ajax.components.ConfigurableComponent.prototype.importConfiguration = function()
{
    // This is where custom properties can be imported from the "this.imported" object
}

//-----------------------------------------------------------------------------
// This menthod should be overridden to provide a relevant menu for the object
// OVERRIDE 3
ajax.components.ConfigurableComponent.prototype.createConfigurationMenu = function()
{
    /*
    Typical things to do here:
    1) define self closure.
    2) Create Menu
    this.configurationMenu = ajax.lang.safeNew("ajax.components.Menu", this.doc, "", 200, 120);
    
    2) Create function handlers for each option
    var onEnabledSelectDelegate = function(e)
    {   
        ajax.debug.Output.writeLn("You clicked on the Enabled Option: " + this.checked);
        self.configurationMenu.hide();
    }
    
    3) Create Menu Items themselves
    var displayFlags = ajax.components.MenuItemDisplayFlags;
    var flags = displayFlags.Image | displayFlags.Text | displayFlags.Checkbox;
    
    var item   = ajax.lang.safeNew("ajax.components.MenuItem",
        this.doc, "Text here", "", "EXAMPLE", null, flags, this.extendedProperties.enabled);
        
    4) Attach event handlers
    item.getEvent(this.window, "onSelected").addListener(onEnabledSelectDelegate);   
    
    5) Attach Items to menu
    this.configurationMenu.addMenuItem(item);       
    
    6) Add a delegate to the document mouseup to hide the menu
    ajax.lang.getEvent(this.window, this.doc, "onmouseup").addListener(function(e)
        {
            self.configurationMenu.hide();
        }
    );
    
    And that's it. Following is a simple menu to show something as default
    */ 
    

    // Create menu, add items, add handlers for the items, add (document level) handler to hide menu.
    this.configurationMenu = ajax.lang.safeNew("ajax.components.Menu", this.doc, "", 200, 100);
    this.configurationMenu.animated = true;
    this.configurationMenu.setWideBackground(true);
    
    var onConfigurationSelectDelegate = function(e)
    {
        alert("You clicked " + this);
        e.cancelBubble = true;
        return false;
    };
    
    var items = ["Configuration Menu", "goes here", "-", "Enabled"];
    var displayFlags = ajax.components.MenuItemDisplayFlags;
    
    for (var i = 0; i < items.length; i++)
    {    
        var item = ajax.lang.safeNew("ajax.components.MenuItem", 
            this.doc, items[i], "", "KEY_" + i, null, displayFlags.Image | displayFlags.Checkbox, true);            
            
        this.configurationMenu.addMenuItem(item);
        item.getEvent(this.window, "onSelected").addListener(onConfigurationSelectDelegate);
    }
    
    // Add a delegate to the document click to hide this menu
    var self = this;
    ajax.lang.getEvent(this.window, this.doc, "onmouseup").addListener(function(){ self.configurationMenu.hide(); });
    
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.toString = function()
{
    return "ajax.components.ConfigurableComponent";
}





//-----------------------------------------------------------------------------
// This method probably doesn't need to be overridden. One reason to do so would be to 
// update menu items (checked) if somehow the base data has changed by another process (than through the menu).
ajax.components.ConfigurableComponent.prototype.showConfigurationMenu = function(e)
{    
    // Get a handle back to ourself from the object clicked
    var self = this.configureObject;
    if (self.configurationMenu == null)
        self.createConfigurationMenu(); 
    // Show the menu hanging off this object
    self.configurationMenu.show(null, null, this);                   
}



//-----------------------------------------------------------------------------
// These two methods would probably NOT be overridden as they are so standard.
// - they just set & get data from the import & export objects. 
// They are wired in the constructor to listen for the Load(ed) and save(d)
// events coming back from the Content Loaders.
ajax.components.ConfigurableComponent.prototype.onConfigureLoadHandler = function(e)
{
    // The options have now been loaded into this.imported
    var text = e.responseText;
    if (text != "")
    {
        this.imported = text.toJsonObject();
        this.importConfiguration(); // This would be overridden with 
        ajax.debug.Output.writeLn("Loaded " + this + " config: " + text);
    }
    else    
        ajax.debug.Output.writeLn(this + ".onConfigureLoadHandler was passed a blank string from the server.");        
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.onConfigureSaveHandler = function(e)
{        
    var text = e.responseText;
    if (text != "")
    {
        this.imported = text.toJsonObject();
        this.importConfiguration();  
        ajax.debug.Output.writeLn("Saved " + this + " config: " + text);      
    }
    else
        ajax.debug.Output.writeLn(this + ".onConfigureSaveHandler was passed a blank string from the server."); 
}



//-----------------------------------------------------------------------------
// I see no reason to need to override these methods
ajax.components.ConfigurableComponent.prototype.enableConfigureLoad = function(url, loadParams)
{
    this.configureLoad = ajax.lang.safeNew("ajax.net.ContentLoader", this, this.onConfigureLoad, null, url, "POST", loadParams);
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.enableConfigureSave = function(url, saveParams)
{
    this.configureSave = ajax.lang.safeNew("ajax.net.ContentLoader", this, this.onConfigureSave, null, url, "POST", saveParams);    
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.loadConfiguration = function()
{
    if (!this.configureLoad)
        return;
    this.configureLoad.sendRequest();
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.saveConfiguration = function()
{
    // Export required data
    this.exportConfiguration();    
    
    if (!this.configureSave)
        return;
        
    // Get JSON from object (without functions)
    var json = this.exported.toJsonString(false);
       
    // this will fire the this.onConfigureSaveDelegate, which will route the event out to anyone interested.
    this.configureSave.sendRequest("json=" + escape(json));
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.addConfigureTrigger = function(obj)
{
    // Add without duplicate
    this.configureTriggers.append(obj, true);  
    
    // add us as the configureObject
    obj.configureObject = this;
    
    // add an event delegate to bring up the configuration menu 
    ajax.lang.getEvent(this.window, obj, "onclick").addListener(this.showConfigurationMenu);
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.removeConfigureTrigger = function(obj)
{
    // remove the trigger obj
    this.configureTriggers.remove(obj);
    
    // Remove us
    obj.configureObject = null;
    
    // Remove delegate
    ajax.lang.getEvent(this.window, obj, "onclick").removeListener(this.showConfigurationMenu);
}

//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.prototype.toClassName = function()
{
    return ajax.lang.getClassName("ajax.components.ConfigurableComponent");
}


//-----------------------------------------------------------------------------
ajax.components.ConfigurableComponent.cast = function(obj)
{///<returns type="ajax.components.ConfigurableComponent"/>
    return obj
}


